-- Copyright (c) 2025 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local skynet = require 'skynet'
local m_mdb = require 'mc.mdb'
local log = require 'mc.logging'
local mc_context = require 'mc.context'

local test_utils = {}

local PATH_TRUSTED_COMPONENT_FMT = "/bmc/kepler/Chassis/%s/TrustedComponents/%s"
local INTF_TRUSTED_COMPONENT     = "bmc.kepler.RoT.TrustedComponent"

local PATH_COMPONENT_INTEGRITY_FMT = "/bmc/kepler/Chassis/%s/TrustedComponents/%s/ComponentIntegrity/%s"
local INTF_COMPONENT_INTEGRITY     = "bmc.kepler.RoT.ComponentIntegrity"
local INTF_MEASUREMENT_SET         = "bmc.kepler.RoT.ComponentIntegrity.MeasurementSet"

local PATH_MEASUREMENT_FMT = "/bmc/kepler/Chassis/%s/TrustedComponents/%s/ComponentIntegrity/%s/Measurements/%s"
local INTF_MEASUREMENT     = "bmc.kepler.RoT.ComponentIntegrity.SPDMMeasurement"

local PATH_TC_CERTIFICATE_FMT = "/bmc/kepler/Chassis/%s/TrustedComponents/%s/Certificates/%s"
local INTF_CERTIFICATE        = "bmc.kepler.CertificateService.Certificate"

local initiator_info = mc_context.new("IT", "Administrator", "127.0.0.1")

-- 设置日志级别
function test_utils.set_log_level(bus, apps, level)
    for _, app in ipairs(apps) do
        local service = string.format('bmc.kepler.%s', app)
        local path = string.format('/bmc/kepler/%s/MicroComponent', app)
        local intf = 'bmc.kepler.MicroComponent.Debug'
        local ok, err = pcall(bus.call, bus, service, path, intf, 'SetDlogLevel', 'a{ss}sy', mc_context.new(), level, 0)
        if not ok then
            log:error('Set app [%s] log level [%s] failed, error: %s', app, level, err)
        else
            log:notice('Set app [%s] log level [%s] successfully.', app, level)
        end
    end
end

local function get_object(bus, path, intf)
    local ok, obj
    for _ = 1, 5 do -- 5次重试
        ok, obj = pcall(m_mdb.get_object, bus, path, intf)
        if ok then
            return obj
        end
        skynet.sleep(100) -- 重试间隔100 * 10ms
    end

    error(obj)
end

function test_utils.get_trusted_component_property(bus, chassis_id, device_name, prop_name)
    local rpc_path = string.format(PATH_TRUSTED_COMPONENT_FMT, tostring(chassis_id), device_name)
    local mobj = get_object(bus, rpc_path, INTF_TRUSTED_COMPONENT)
    return mobj[prop_name]
end

function test_utils.get_component_integrity_property(bus, chassis_id, device_name, integrity_id, prop_name)
    local rpc_path = string.format(PATH_COMPONENT_INTEGRITY_FMT, tostring(chassis_id), device_name,
        tostring(integrity_id))
    local mobj = get_object(bus, rpc_path, INTF_COMPONENT_INTEGRITY)
    return mobj[prop_name]
end

function test_utils.get_measurement_set_property(bus, chassis_id, device_name, integrity_id, prop_name)
    local rpc_path = string.format(PATH_COMPONENT_INTEGRITY_FMT, tostring(chassis_id), device_name,
        tostring(integrity_id))
    local mobj = get_object(bus, rpc_path, INTF_MEASUREMENT_SET)
    return mobj[prop_name]
end

function test_utils.call_get_signed_measurement(bus, chassis_id, device_name, integrity_id, measurement_indices,
    slot_id, nonce)
    local rpc_path = string.format(PATH_COMPONENT_INTEGRITY_FMT, tostring(chassis_id), device_name,
        tostring(integrity_id))
    local mobj = get_object(bus, rpc_path, INTF_MEASUREMENT_SET)
    return mobj:SPDMGetSignedMeasurements_PACKED(initiator_info, measurement_indices, slot_id, nonce):unpack()
end

function test_utils.get_measurement_property(bus, chassis_id, device_name, integrity_id, id, prop_name)
    local rpc_path = string.format(PATH_MEASUREMENT_FMT, tostring(chassis_id), device_name, tostring(integrity_id),
        tostring(id))
    local mobj = get_object(bus, rpc_path, INTF_MEASUREMENT)
    return mobj[prop_name]
end

function test_utils.get_certificate_property(bus, chassis_id, device_name, cert_id, prop_name)
    local rpc_path = string.format(PATH_TC_CERTIFICATE_FMT, tostring(chassis_id), device_name, tostring(cert_id))
    local mobj = get_object(bus, rpc_path, INTF_CERTIFICATE)
    return mobj[prop_name]
end

return test_utils